#include <iostream>
#include <iomanip>
#include <cstdint>
#include <unordered_map>
#include <unordered_set>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <termios.h>
#include <sys/wait.h>
#include <fcntl.h>

#include "MyShell.h"
#include "MyTextFileReaderAndWriterInterface.h"
#include "Trie.h"

mysh::MyShell* mysh::MyShell::instance = nullptr;

std::mutex mysh::MyShell::mtx;

// 构造函数
mysh::MyShell::MyShell()
{
    // 获取用户信息
    mysh::cur_uid = getuid();
    mysh::cur_user_info = getpwuid(mysh::cur_uid);
    // 获取主机名
    char host_name[256] = {0};
    gethostname(host_name, 256);
    mysh::cur_host_name = std::string(host_name);
    // 利用环境变量PWD构造资源管理器，使MyShell的工作路径为当前路径
    mysh::resource_manager = new mysh::ResourceManager(std::string(getenv("PWD")));
    // 特殊路径
    mysh::unique_path['~'] = std::string(getenv("HOME"));
    mysh::unique_path['-'] = mysh::unique_path['~'];
    mysh::unique_path['.'] = mysh::resource_manager->root_path.string();
    // 创建文本文件读写器
    textfilerw::TextFileReaderAndWriter tfrw = textfilerw::TextFileReaderAndWriter();
    // 读取配置文件并创建JSON解析器
    myjson::JSONParser json_parser = myjson::JSONParser(tfrw.readIntoOneString(mysh::unique_path['~'] + "/my-shell/.myshrc"));
    // 通过parse方法解析出JNode
    mysh::my_shell_configurations = json_parser.parse();
    // 配置mysh
    this->configurate();
    // 读取历史记录文件的命令历史，并将命令历史记录索引置为命令历史记录数组的大小
    std::vector<std::string> assist = tfrw.read(mysh::mysh_history_file_name);
    std::int32_t i = assist.size() > mysh::mysh_history_max_size ? assist.size() - mysh::mysh_history_max_size : 0;
    for (; i < assist.size(); i++)
    {
        mysh::mysh_history_commands.push_back(assist[i]);
    }
    mysh::mysh_history_index = mysh::mysh_history_commands.size();
    // 退出状态默认为0
    mysh::exit_status = 0;
}

// 析构函数
mysh::MyShell::~MyShell()
{
    mysh::cur_user_info = nullptr;
    mysh::cur_host_name.clear();
    delete mysh::resource_manager;
    mysh::mysh_history_commands.clear();
    delete mysh::internal_commands_trie;
    mysh::internal_commands_trie = nullptr;
    delete mysh::external_commands_trie;
    mysh::external_commands_trie = nullptr;
    for (myds::Trie* trie : mysh::system_commands_tries)
    {
        delete trie;
        trie = nullptr;
    }
    mysh::system_commands_tries.clear();
}

// 获取MyShell单例
mysh::MyShell* mysh::MyShell::getInstance()
{
    if (mysh::MyShell::instance == nullptr)
    {
        std::lock_guard<std::mutex> lock(mysh::MyShell::mtx);
        if (mysh::MyShell::instance == nullptr)
        {
            mysh::MyShell::instance = new mysh::MyShell();
        }
    }
    return mysh::MyShell::instance;
}

// 销毁MyShell单例
void mysh::MyShell::destroyInstance()
{
    if (mysh::MyShell::instance == nullptr)
    {
        return;
    }
    else
    {
        std::lock_guard<std::mutex> lock(mysh::MyShell::mtx);
        delete mysh::MyShell::instance;
        mysh::MyShell::instance = nullptr;
    }
}

// 配置函数
void mysh::MyShell::configurate()
{
    // 将mysh配置信息对应的JNode转为unordered_map类型
    std::unordered_map<std::string, myjson::JNode> json_nodes = static_cast<std::unordered_map<std::string, myjson::JNode>>(mysh::my_shell_configurations);
    // 获取命令历史记录最大记录量
    mysh::mysh_history_max_size = static_cast<std::int64_t>(json_nodes["mysh-history-max-size"]);
    // 获取mysh路径
    mysh::mysh_path = mysh::parseString(static_cast<std::string>(json_nodes["mysh-path"]));
    // 获取命令历史记录文件的文件名(包含路径)
    mysh::mysh_history_file_name = mysh::mysh_path + "/" + ".mysh_history";
    // 获取mysh配置文件的文件名(包含路径)
    mysh::myshrc_file_name = mysh::mysh_path + "/" + ".myshrc";
    // 获取内部命令
    std::vector<myjson::JNode> internal_commands_json_nodes = static_cast<std::vector<myjson::JNode>>(json_nodes["internal-commands"]);
    for (std::uint32_t i = 0; i < internal_commands_json_nodes.size(); i++)
    {
        std::string cur_command = static_cast<std::string>(internal_commands_json_nodes[i]);
        mysh::internal_commands[cur_command] = i;
        mysh::internal_commands_trie->insert(cur_command);
    }
    // 获取外部命令路径
    mysh::external_commands_path = mysh::parseString(static_cast<std::string>(json_nodes["external-commands-path"]));
    // 获取所有外部命令并创建外部命令字典树
    std::vector<std::string> external_commands_array = mysh::ResourceManager::createFilesArrayFromRootPath(mysh::external_commands_path);
    for (const std::string& external_command : external_commands_array)
    {
        mysh::external_commands.insert(external_command);
        mysh::external_commands_trie->insert(external_command);
    }
    // 获取所有系统命令路径
    mysh::system_commands_paths = mysh::split(mysh::parseString(static_cast<std::string>(json_nodes["system-commands-paths"])), ':');
    // 构建所有可能的系统命令的字典树
    for (const std::string& system_commands_path : mysh::system_commands_paths)
    {
        std::vector<std::string> system_commands_array = mysh::ResourceManager::createFilesArrayFromRootPath(system_commands_path);
        myds::Trie* cur_system_trie = new myds::Trie();
        for (const std::string& system_command : system_commands_array)
        {
            cur_system_trie->insert(system_command);
        }
        mysh::system_commands_tries.push_back(cur_system_trie);
    }
    // 获取所有别名(或变量)及
    std::unordered_map<std::string, myjson::JNode> alias_json_node = static_cast<std::unordered_map<std::string, myjson::JNode>>(json_nodes["alias"]);
    for (std::unordered_map<std::string, myjson::JNode>::iterator iter = alias_json_node.begin(); iter != alias_json_node.end(); iter++)
    {
        std::string key = iter->first;
        myjson::JNode value = iter->second;
        mysh::alias[key] = static_cast<std::string>(value);
    }
    // 获取刷新延时
    mysh::refresh_delay = static_cast<std::int64_t>(json_nodes["refresh-delay"]);
    // 删除mysh配置信息中的别名(或变量)节点
    mysh::my_shell_configurations.deleteObjectKey("alias");
}

// 主循环
void mysh::MyShell::mainLoop()
{
    // 主循环，由if_break控制是否退出
    while (!mysh::if_break)
    {
        // 打印信息
        mysh::printInfo();
        // 输入命令
        std::string command = mysh::inputCommand();
        // 执行行命令
        mysh::Executor::executeLineCommand(command);
    }
}

// 获取退出状态
std::uint32_t mysh::MyShell::getExitStatus()
{
    return mysh::exit_status;
}
